import os

from flask import Flask, make_response, jsonify, session, send_from_directory, url_for, request, render_template, \
    current_app, abort, g, send_file, Blueprint

from config.app_config import AppConfig
from insects_detection.ftp_imgserver import MyFTP
from insects_detection.project_utils import project_tools
from insects_detection.insects_utils import insects_tools
from celery_task.classify_task import recompute_detailed_insects_info
from celery_task.imgprocess_task import process_sticky_card_imgs
from celery_task.update_insects_task import recompute_insects_distribution
from celery.result import AsyncResult
import datetime
from utils.redis_utils import RedisTool
from utils.result_utils import ResultUtil
import time
import json
from flask_restplus import Api, Resource, Namespace

# 连接redis数据库
# r = redis.StrictRedis(host='39.102.44.159', port=6379, db=0, password='inetlabredis', decode_responses=True)
r = RedisTool(host='39.102.44.159', port=6379, db=0, password='inetlabredis')
# 指定病虫害识别相关工作目录
project_root_dir=project_tools.project_root_path()+os.sep+'insects_detection'
project_tools.prepare_working_dirs(project_root_dir)
processed_gallery_path = project_root_dir + os.sep + project_tools.processed_img_dirname
chas_data_path = project_root_dir + os.sep + project_tools.characteristic_dirname
model_path = project_root_dir + os.sep + project_tools.models_dirname + os.sep + project_tools.model_name

insects_api = Blueprint("insects_api", __name__)
api = Api(insects_api, version='1.0', title='insects detection API',
          description='温室病虫害监测接口文档')
ns = api.namespace('insects_api', description='温室病虫害识别相关接口')


@ns.route('/get_insects_info/', '/get_insects_info/<cached>', defaults={'cached': 'c'})
class GetInsectsInfo(Resource):
    def get(self, cached):
        '''
        获取当前虫害计数信息（rarely used）
        :param cached:
        :return: 如果开启缓存则从redis拉取当日虫害计数信息，若不开启缓存则提交异步任务重新计算，并返回监控该任务执行情况的url地址
        '''
        if "cached_insects_results" in session and cached == 'c':
            print(cached)
            response = make_response(session["cached_insects_results"])
        else:
            gallery_path = "D:\python\workspace\insects_detection\processed_imgs"
            gh_insects_info = insects_tools.green_house_insects_info(gallery_path)
            time_str = datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d %H:%M:%S')
            gh_insects_info['update_time'] = time_str
            response = make_response(jsonify(gh_insects_info), 200)
            session["cached_insects_results"] = gh_insects_info
        return response


# 请求获得每类昆虫详细信息的调用接口
@ns.route('/get_detailed_insects_info/', '/get_detailed_insects_info/<cached>', defaults={'cached': 'c'})
class DetailedInfo(Resource):
    def get(self, cached):
        """
        获取当前虫种分类和计数详情
        :param cached:
        :return: 若选择缓存，则直接从redis获取当日虫害详情信息，否则提交异步任务，并返回监控该异步任务完成情况的url地址
        """
        # 若从缓存获取
        # info_key = str('insects:' + time.strftime("%Y-%m-%d", time.localtime()))  # 键值示例:insects:2021-06-19
        info_key = 'insects:May:test'
        if cached == 'c':
            if r.read(info_key) is None:
                response = make_response(jsonify(
                    {'code': 20000, 'message': 'No data found in cache, please submit a task first', 'data': {}}), 200)
            else:
                detailed_insects_info = r.read(info_key)
                response = make_response(jsonify(
                    {'code': 20000, 'message': 'ok', 'data': detailed_insects_info}), 200)
        # 提交异步任务，重新计算
        else:
            project_root_dir = project_tools.project_root_path() + '\\' + 'insects_detection'
            chas_data_path = project_root_dir + '\\' + project_tools.characteristic_dirname
            model_path = project_root_dir + '\\' + project_tools.models_dirname + '\\' + project_tools.model_name
            classify_task = recompute_detailed_insects_info.apply_async(args=[chas_data_path, model_path])
            response = make_response(jsonify(
                {'code': 20000, 'message': 'Task submitted',
                 'data': {'task_monitor': url_for('task_status', task_id=classify_task.id)}}), 202)
        return response


@ns.route('/get_recent_insects_info/', '/get_recent_insects_info/<date_range>')
class RecentInfo(Resource):
    def get(self, date_range='not_specified'):
        '''
        获取指定日期范围内的虫种详情数据
        :param date_range:
        :return:指定日期范围内的详情数据较多，仅提供从缓存获取的方式，默认日期范围为调用该接口的月份往前推6个月
        '''
        # 若从缓存获取
        # info_key = str('insects:' + time.strftime("%Y-%m-%d", time.localtime()))  # 键值示例:insects:2021-06-19
        matched_keys = r.get_matched_keys('insects:*:test')
        if matched_keys:
            detailed_insects_info = r.mread(matched_keys)
            sorted_detailed_insects_info = ResultUtil.sort_result_by_date(detailed_insects_info, 'last_update_time')
            response = make_response(jsonify(
                {'code': 20000, 'message': 'ok', 'data': sorted_detailed_insects_info}), 200)
        else:
            response = make_response(jsonify(
                {'code': 20000, 'message': 'No data found, please submit at least one detection task~', 'data': {}}),
                200)
        return response


@ns.route('/visual_insects_count/<path:img_path>')
class VisualImg(Resource):
    def get(self, img_path='not specified'):
        '''
        输入一张粘虫板图片，输出打上计数标记的base64格式图片
        :param img_path:
        :return:base64格式图片
        '''
        # 从缓存获取
        r_key = 'key placeholder'
        if False:
            if r.read(r_key) is None:
                response = make_response(jsonify(
                    {'code': 20000, 'message': 'No data found in cache, please submit a task first', 'data': {}}), 200)
            else:
                img_b64 = r.read(r_key)
                response = make_response(jsonify(
                    {'code': 20000, 'message': 'ok', 'data': img_b64}), 200)
        # 提交异步任务，重新计算
        else:
            if project_tools.system_platform == 'linux':
                img_path = os.sep + img_path
            count_task = process_sticky_card_imgs.apply_async(args=[img_path, False, None, True])
            response = make_response(jsonify(
                {'code': 20000, 'message': 'Task submitted',
                 'data': {'task_monitor': url_for('task_status', task_id=count_task.id)}}), 202)
        return response


@ns.route('/get_visual_history/')
class VisualHistory(Resource):
    def get(self):
        my_ftp = MyFTP(AppConfig.host)
        my_ftp.login("test", "inetlab")
        detailed_file_list_info = my_ftp.dirs()
        filename_list = my_ftp.get_dir_filename(detailed_file_list_info)
        file_urls = []
        for name in filename_list:
            file_urls.append('http://' + AppConfig.host + '/test/' + name)
        my_ftp.close()
        response = make_response(jsonify(
            {'code': 20000, 'message': 'ok',
             'data': {'image_urls': file_urls}}), 200)
        return response


@ns.route('/update_insects_info/<path:gallery_path>')
class UpdateInsectsInfo(Resource):
    def get(self, gallery_path):
        '''
        异步执行虫情计算，包含原始图像预处理、虫害特征提取，实时分类操作
        :return:分类后该采集周期的宏观虫情数据
        '''
        if project_tools.system_platform == 'linux':
            gallery_path = os.sep + gallery_path
        update_task = recompute_insects_distribution.apply_async(args=[gallery_path, processed_gallery_path, chas_data_path, model_path])
        response = make_response(jsonify(
            {'code': 20000, 'message': 'Task submitted',
             'data': {'task_monitor': url_for('task_status', task_id=update_task.id)}}), 202)
        return response

@ns.route('/task_status/', '/task_status/<task_id>', endpoint='task_status')
class TaskStatus(Resource):
    def get(self, task_id=''):
        '''
        获取异步任务的执行情况
        :param task_id:
        :return: 异步任务执行情况（state），当前已完成的项目（current），本任务包含的项目总数（total），任务当前的状态（status）
        '''
        task = recompute_detailed_insects_info.AsyncResult(task_id)
        if task_id == '':
            response = {
                'state': 'No Task',
                'current': 'None',
                'total': 'None',
                'status': 'Oops... there is no submitted task~',  # 报错的具体异常
            }
        elif task.state == 'PENDING':  # 在等待
            response = {
                'state': task.state,
                'current': 0,
                'total': 1,
                'status': 'Pending...'
            }
        elif task.info != None and task.state != 'FAILURE':  # 没有失败
            response = {
                'state': task.state,  # 状态
                # meta中的数据，通过task.info.get()可以获得
                'current': task.info.get('current', 0),  # 当前循环进度
                'total': task.info.get('total', 1),  # 总循环进度
                'status': task.info.get('status', '')
            }
            if 'result' in task.info:
                response['result'] = task.info['result']
        else:
            # 后端执行任务出现了一些问题
            response = {
                'state': task.state,
                'current': 1,
                'total': 1,
                'status': str(task.info),  # 报错的具体异常
            }
        return make_response(jsonify(
            {'code': 20000, 'message': 'ok', 'data': response}), 200)
